package org.gikolet.ch2.android.dao;

import java.util.ArrayList;
import java.util.List;

import org.gikolet.ch2.android.dao.Schema.Boards;
import org.gikolet.ch2.android.dao.Schema.Boards.Columns;
import org.gikolet.ch2.dao.BoardsDao;
import org.gikolet.ch2.dao.DaoException;
import org.gikolet.ch2.data.Board;

import roboguice.inject.ContextScoped;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabase;

import com.google.inject.Inject;

@ContextScoped
public class AndroidBoardsDao implements BoardsDao {

	private static final String[] COLUMNS = { Columns.ID.column(),
			Columns.HOST_NAME.column(), Columns.PATH.column(),
			Columns.NAME.column() };

	private static final String SELECTION_ID = Columns.ID.column() + " = ?";
	private static final String SELECTION_HOSTNAME_PATH = Columns.HOST_NAME
			.column()
			+ " = ? AND " + Columns.PATH + " = ?";

	@Inject
	private SQLiteDatabase db;

	public AndroidBoardsDao() {
	}

	public void create(Board board) throws DaoException {
		try {
			ContentValues cv = Boards.convert(board);
			cv.remove(Boards.Columns.ID.column());

			long rowid = this.db.insertOrThrow(Boards.TBL_NAME, null, cv);

			board.setId(rowid);

		} catch (SQLiteConstraintException e) {
			throw new DaoException(DaoException.Error.CONSTRAINT, e);

		} catch (SQLException e) {
			throw new DaoException(DaoException.Error.ERROR, e);
		}
	}

	public Board find(Long id) {
		String[] selectionArgs = new String[] { id.toString() };

		Cursor c = null;

		try {
			c = this.db.query(Boards.TBL_NAME, COLUMNS, SELECTION_ID,
					selectionArgs, null, null, null);

			if (!c.moveToFirst()) {
				throw new DaoException(DaoException.Error.NOT_FOUND);
			}

			return Boards.convert(c);

		} catch (SQLException e) {
			throw new DaoException(DaoException.Error.ERROR, e);

		} finally {
			if (c != null) {
				try {
					c.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public Board findHostNameAndPath(String hostName, String path)
			throws DaoException {
		String[] selectionArgs = new String[] { hostName.toString(),
				path.toString() };

		Cursor c = null;

		try {
			c = this.db.query(Boards.TBL_NAME, COLUMNS,
					SELECTION_HOSTNAME_PATH, selectionArgs, null, null, null);

			if (!c.moveToFirst()) {
				throw new DaoException(DaoException.Error.NOT_FOUND);
			}

			return Boards.convert(c);

		} catch (SQLException e) {
			throw new DaoException(DaoException.Error.ERROR, e);

		} finally {
			if (c != null) {
				try {
					c.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public List<Board> findAll() {
		Cursor c = null;

		try {
			c = this.db.query(Boards.TBL_NAME, COLUMNS, null, null, null, null,
					null);

			List<Board> boards = new ArrayList<Board>();

			if (c.moveToFirst()) {
				do {
					boards.add(Boards.convert(c));

				} while (c.moveToNext());
			}

			return boards;

		} catch (SQLException e) {
			throw new DaoException(DaoException.Error.ERROR, e);

		} finally {
			if (c != null) {
				try {
					c.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public void update(Board board) {
		try {
			ContentValues cv = Boards.convert(board);
			cv.remove(Boards.Columns.ID.column());

			String[] whereArgs = { board.getId().toString() };

			int count = this.db.update(Boards.TBL_NAME, cv, SELECTION_ID,
					whereArgs);

			if (count == 0) {
				throw new DaoException(DaoException.Error.NOT_FOUND);
			}

		} catch (SQLException e) {
			throw new DaoException(DaoException.Error.ERROR, e);
		}
	}

	public void delete(Long id) {
		try {
			String[] whereArgs = new String[] { id.toString() };

			int count = this.db
					.delete(Boards.TBL_NAME, SELECTION_ID, whereArgs);

			if (count == 0) {
				throw new DaoException(DaoException.Error.NOT_FOUND);
			}

		} catch (SQLException e) {
			throw new DaoException(DaoException.Error.ERROR, e);
		}
	}

	public void deleteAll() {
		try {
			this.db.delete(Boards.TBL_NAME, null, null);

		} catch (SQLException e) {
			throw new DaoException(DaoException.Error.ERROR, e);
		}
	}
}
